package com.ssy.lingxi.marketing.serviceimpl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.json.JSONUtil;
import com.querydsl.core.BooleanBuilder;
import com.querydsl.core.types.Projections;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.ssy.lingxi.common.constant.Constants;
import com.ssy.lingxi.common.response.Wrapper;
import com.ssy.lingxi.component.rabbitMQ.service.IRabbitMQUtils;
import com.ssy.lingxi.component.redis.service.IRedisStringUtils;
import com.ssy.lingxi.marketing.api.model.constant.ActivityRecordTypeEnum;
import com.ssy.lingxi.marketing.api.model.constant.MkFeignConstants;
import com.ssy.lingxi.marketing.api.model.constant.MkRedisKeyConstants;
import com.ssy.lingxi.marketing.api.model.request.GoodsSalesAddReq;
import com.ssy.lingxi.marketing.api.model.request.GoodsSalesItemActivityReq;
import com.ssy.lingxi.marketing.api.model.request.GoodsSalesItemReq;
import com.ssy.lingxi.marketing.api.model.request.GoodsSalesReq;
import com.ssy.lingxi.marketing.api.model.response.CartGiveResponse;
import com.ssy.lingxi.marketing.entity.activity.ActivityGoodsDO;
import com.ssy.lingxi.marketing.entity.activity.QActivityGoodsCouponDO;
import com.ssy.lingxi.marketing.entity.activity.QActivityGoodsDO;
import com.ssy.lingxi.marketing.entity.activity.QActivityGoodsSubsidiaryDO;
import com.ssy.lingxi.marketing.model.dto.ActivityGoodsSubsidiaryDto;
import com.ssy.lingxi.marketing.model.dto.SubsidiaryDto;
import com.ssy.lingxi.marketing.model.vo.activity.request.ActivityGoodsSalesReq;
import com.ssy.lingxi.marketing.model.vo.activity.response.ActivityGoodsRestrictNumResp;
import com.ssy.lingxi.marketing.model.vo.activity.response.ActivityGoodsSalesResp;
import com.ssy.lingxi.marketing.service.IActivityExecuteService;
import com.ssy.lingxi.marketing.service.IActivityGoodsCacheService;
import com.ssy.lingxi.marketing.serviceimpl.component.activity.ActivityGoodsHandleComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 活动缓存服务实现类
 * @author ds, yzc
 * @version 2.0.0
 * @date 2021/8/19
 */
@Slf4j
@Service
public class ActivityGoodsCacheServiceImpl implements IActivityGoodsCacheService {

    @Autowired
    private IRedisStringUtils redisStringUtils;

    @Resource
    private ActivityGoodsHandleComponent activityGoodsHandleComponent;

    @Resource
    private JPAQueryFactory queryFactory;
    @Resource
    private IRabbitMQUtils rabbitMQUtils;
    @Resource
    private IActivityExecuteService activityExecuteService;

    /**
     * 更新缓存活动销量
     * 缓存结构如下：
*          name                key                                       type
     *      总销量              TK=前缀:活动id:skuid                       string
     *      [移到mq中处理]活动商品参与客户数   TK:后缀                                    zset
     *      活动商品会员已购数   前缀:活动id field=skuid:memberId:roleId
     *      订单商品活动集合     前缀:订单号 field=skuId  val=json{"belongType":1,"acitivityId":1} hash
     * @param goodsSalesReq
     * @return
     */
    @Override
    public Wrapper<Void> updateGoodsSales(GoodsSalesReq goodsSalesReq) {
        log.info("准备更新营销活动销量：req:{}", JSONUtil.toJsonStr(goodsSalesReq));
        List<GoodsSalesAddReq> salesAddReqs=new ArrayList<>();
        boolean isRefund = ActivityRecordTypeEnum.REFUND.getCode().equals(goodsSalesReq.getRecordType());
        for(GoodsSalesItemReq item :goodsSalesReq.getItemList()){
            String orderKey=MkRedisKeyConstants.getOrderSkuJoinActivitiesKey(item.getOrderNo());
            List<GoodsSalesItemActivityReq> activityList=item.getActivityList();
            //如果为退货
            if(isRefund){
                //查询活动执行中，是否存在参与活动的记录
                List<GoodsSalesItemActivityReq> orderJoinActivity = activityExecuteService.getOrderJoinActivity(item.getOriginOrderNo(), item.getSkuId());
                if(CollectionUtil.isEmpty(orderJoinActivity)){
                    log.warn("此退货单未参与过活动：item:{}，orderKey:{}",JSONUtil.toJsonStr(item),orderKey);
                    continue;
                }
                activityList = orderJoinActivity;
            }
            //遍历sku参与的活动
            for(GoodsSalesItemActivityReq act:activityList) {
                String salesKey = MkRedisKeyConstants.getActivitySkuSalesKey(act.getBelongType(), act.getActivityId(), item.getSkuId());
                //1更新活动商品总销量
                Double incrementNum = redisStringUtils.increment(salesKey, item.getNum(), Constants.REDIS_MARKETING_INDEX);
                if (incrementNum == null) {
                    Boolean flag = redisStringUtils.set(salesKey, item.getNum() + "",MkRedisKeyConstants.CACHE_EXPIRED, Constants.REDIS_MARKETING_INDEX);
                    if (flag==null||!flag) {
                        log.warn("更新活动商品总销量失败：item:{}", JSONUtil.toJsonStr(item));
                    }
                } else if (incrementNum == 0) {
                    log.warn("更新活动商品总销量失败2：item:{}", JSONUtil.toJsonStr(item));
                }
                //3更新活动商品会员已购数量
                String memberBuyNumKey = MkRedisKeyConstants.getActivitySkuMemberBuyNumKey(act.getBelongType(), act.getActivityId());
                String memberBuyNumField = item.getSkuId() + ":" + goodsSalesReq.getMemberId() + ":" + goodsSalesReq.getRoleId();
                Double memberIncrementNum = redisStringUtils.hIncrement(memberBuyNumKey, memberBuyNumField, item.getNum(), Constants.REDIS_MARKETING_INDEX);
                if (memberIncrementNum == null) {
                    Boolean result = redisStringUtils.hSet(memberBuyNumKey, memberBuyNumField, item.getNum() + "",MkRedisKeyConstants.CACHE_EXPIRED, Constants.REDIS_MARKETING_INDEX);
                    if (result==null||!result) {
                        log.warn("更新活动商品会员已购数量失败：item:{}", JSONUtil.toJsonStr(item));
                    }
                } else if (memberIncrementNum == 0) {
                    log.warn("更新活动商品会员已购数量失败2：item:{}", JSONUtil.toJsonStr(item));
                }

                //添加活动商品销量更新到mq
                GoodsSalesAddReq vo=new GoodsSalesAddReq();
                vo.setRecordType(goodsSalesReq.getRecordType());
                vo.setBelongType(act.getBelongType());
                vo.setActivityId(act.getActivityId());
                vo.setSkuId(item.getSkuId());
                vo.setNum(item.getNum());

                vo.setMemberId(goodsSalesReq.getMemberId());
                vo.setRoleId(goodsSalesReq.getRoleId());
                vo.setMemberName(goodsSalesReq.getMemberName());
                vo.setShopId(goodsSalesReq.getShopId());
                vo.setShopName(goodsSalesReq.getShopName());
                vo.setAmount(item.getAmount());
                vo.setOrderId(item.getOrderId());
                vo.setOrderNo(item.getOrderNo());
                vo.setOriginOrderNo(item.getOriginOrderNo());
                vo.setOrderTime(goodsSalesReq.getOrderTime());
                rabbitMQUtils.sendMsg(MkFeignConstants.MK_GOODS_SALES_EXCHANGE, MkFeignConstants.MK_GOODS_SALESROUTINGKEY, JSONUtil.toJsonStr(vo));
            }
            //4保存订单商品参与的活动集合【取消订单时减活动销量用】
            boolean isOrder = ActivityRecordTypeEnum.ORDER.getCode().equals(goodsSalesReq.getRecordType());
            if(isOrder) {
                Boolean orderKeyExists = redisStringUtils.hExists(orderKey, item.getSkuId() + "", Constants.REDIS_MARKETING_INDEX);
                if (!orderKeyExists) {
                    Boolean result = redisStringUtils.hSet(orderKey, item.getSkuId() + "", JSONUtil.toJsonStr(item.getActivityList()), MkRedisKeyConstants.TEMP_EXPIRED, Constants.REDIS_MARKETING_INDEX);
                    if (result == null || !result) {
                        log.warn("保存订单商品参与的活动集合失败：item:{}", JSONUtil.toJsonStr(item));
                    }
                }
            }
        }
        log.info("更新营销活动销量完成");
        return Wrapper.success();
    }

    @Override
    public ActivityGoodsSalesResp getGoodsSale(ActivityGoodsSalesReq salesReq) {
        ActivityGoodsSalesResp resp=new ActivityGoodsSalesResp();
        //查询活动商品总销量
        String total = redisStringUtils.get(MkRedisKeyConstants.getActivitySkuSalesKey(salesReq.getBelongType(),salesReq.getActivityId(), salesReq.getSkuId()),Constants.REDIS_MARKETING_INDEX);
        if(total!=null){
            resp.setTotalSales(Double.parseDouble(total));
        }
        //查询会员已购数量
        if(salesReq.getMemberId()!=null&&salesReq.getRoleId()!=null){
            String memberNum = redisStringUtils.hGet(MkRedisKeyConstants.getActivitySkuMemberBuyNumKey(salesReq.getBelongType(),salesReq.getActivityId()), salesReq.getSkuId()+":"+salesReq.getMemberId()+":"+salesReq.getRoleId(), Constants.REDIS_MARKETING_INDEX);
            if(memberNum!=null){
                resp.setMemberNum(Double.parseDouble(memberNum));
            }
        }
        return resp;
    }

    @Override
    public void getActivityGoodsSale(Integer belongType,Long activityId) {
        String searchKeyPrefix=Constants.REDIS_KEY_MARKETING_ACTIVITY_GOODS_SKU_SALES_STATISTICS_PREFIX+ ":"+belongType + ":" + activityId+"*";
        List<String> totalKeys = redisStringUtils.searchKey(searchKeyPrefix, Constants.REDIS_MARKETING_INDEX);
        if(CollectionUtil.isNotEmpty(totalKeys)){
            //活动商品总销量
            totalKeys.forEach(o ->{
                String totalNum = redisStringUtils.get(o, Constants.REDIS_MARKETING_INDEX);
            });
        }
        List<String> customerKey = redisStringUtils.searchKey(searchKeyPrefix, Constants.REDIS_USER_INDEX);
        if(CollectionUtil.isNotEmpty(customerKey)){
           //参与用户
            customerKey.forEach(o ->{
                Long totalNum = redisStringUtils.getZSetSize(o);
            });
        }
    }

    /**
     * 查询活动商品限购数量 TODO 待优化
     * @param activityIds
     * @param skuIds
     * @return key=所属类型_活动id_skuid
     */
    public Map<String,ActivityGoodsRestrictNumResp> getActivityGoodsRestrictNum(List<Long> activityIds, List<Long> skuIds){

        List<ActivityGoodsDO> activityGoodsRestrictNum = activityGoodsHandleComponent.getActivityGoodsRestrictNum(activityIds, skuIds);
        Map<String,ActivityGoodsRestrictNumResp> map=new HashMap<>();
        if(CollectionUtil.isNotEmpty(activityGoodsRestrictNum)){
            activityGoodsRestrictNum.forEach(o ->{
                ActivityGoodsRestrictNumResp resp=new ActivityGoodsRestrictNumResp();
                BeanUtils.copyProperties(o,resp);
                map.put(o.getBelongType()+"_"+o.getActivityId()+"_"+o.getSkuId(),resp);
            });
        }
        return map;
    }

    //查询sku参与换购活动商品的阶梯条件
    public List<ActivityGoodsSubsidiaryDto> selectSkuSwapActivityLadder(Integer belongType,Long activityId, Long skuId,Long subSkuId) {
        QActivityGoodsDO goodsDO = QActivityGoodsDO.activityGoodsDO;
        QActivityGoodsSubsidiaryDO goodsSubsidiaryDO = QActivityGoodsSubsidiaryDO.activityGoodsSubsidiaryDO;

        BooleanBuilder predicates = new BooleanBuilder();
        predicates.and(goodsDO.belongType.eq(belongType));
        predicates.and(goodsDO.activityId.eq(activityId));
        predicates.and(goodsDO.skuId.eq(skuId));
        predicates.and(goodsSubsidiaryDO.skuId.eq(subSkuId));

        JPAQuery<ActivityGoodsSubsidiaryDto> queryJpaQuery = queryFactory.select(Projections.bean(ActivityGoodsSubsidiaryDto.class,
                goodsSubsidiaryDO.limitValue,
                goodsSubsidiaryDO.swapPrice,
                goodsSubsidiaryDO.num))
                .from(goodsDO)
                .innerJoin(goodsSubsidiaryDO).on(goodsDO.id.eq(goodsSubsidiaryDO.activityGoods.id));
        queryJpaQuery.where(predicates);
        return queryJpaQuery.fetch();
    }


    //查询sku参与赠送活动的赠商品
    private List<SubsidiaryDto> selectSubsidiaryList(Integer belongType, Long activityId, Long skuId,Integer groupNo) {
        QActivityGoodsDO goodsDO = QActivityGoodsDO.activityGoodsDO;
        QActivityGoodsSubsidiaryDO goodsSubsidiaryDO = QActivityGoodsSubsidiaryDO.activityGoodsSubsidiaryDO;

        BooleanBuilder predicates = new BooleanBuilder();
        predicates.and(goodsDO.belongType.eq(belongType));
        predicates.and(goodsDO.activityId.eq(activityId));
        predicates.and(goodsDO.skuId.eq(skuId));
        if(groupNo!=null){
            predicates.and(goodsSubsidiaryDO.groupNo.eq(groupNo));
        }
        JPAQuery<SubsidiaryDto> queryJpaQuery = queryFactory.select(Projections.bean(SubsidiaryDto.class,
                goodsSubsidiaryDO.id.as("subGoodsId"),
                goodsSubsidiaryDO.productName.as("name"),
                goodsSubsidiaryDO.skuId.as("id"),
                goodsSubsidiaryDO.num,
                goodsSubsidiaryDO.category,
                goodsSubsidiaryDO.brand,
                goodsSubsidiaryDO.unit,
                goodsSubsidiaryDO.limitValue,
                goodsSubsidiaryDO.groupNo,
                goodsSubsidiaryDO.price,
                goodsSubsidiaryDO.groupPrice,
                goodsSubsidiaryDO.productId,
                goodsSubsidiaryDO.productImgUrl,
                goodsSubsidiaryDO.type))
                .from(goodsDO)
                .innerJoin(goodsSubsidiaryDO).on(goodsDO.id.eq(goodsSubsidiaryDO.activityGoods.id));
        queryJpaQuery.where(predicates);
        return queryJpaQuery.fetch();
    }

    //查询sku参与赠送活动的赠商品
    public List<CartGiveResponse> selectSkuGiveProductList(Integer belongType, Long activityId, Long skuId) {
        List<SubsidiaryDto> subsidiaryDtos = selectSubsidiaryList(belongType, activityId, skuId, null);
        if(CollectionUtil.isEmpty(subsidiaryDtos)){return null;}
        List<CartGiveResponse> cartGiveResponses =new ArrayList<>();
        for(SubsidiaryDto subDto :subsidiaryDtos){
            CartGiveResponse dto=new CartGiveResponse();
            dto.setGiftId(subDto.getSubGoodsId());
            dto.setId(subDto.getId());
            dto.setName(subDto.getName());
            dto.setLimitValue(subDto.getLimitValue());
            dto.setNum(subDto.getNum());
            dto.setGroupNo(subDto.getGroupNo());
            dto.setBrand(subDto.getBrand());
            dto.setCategory(subDto.getCategory());
            dto.setUnit(subDto.getUnit());
            dto.setProductId(subDto.getProductId());
            cartGiveResponses.add(dto);
        }
        return cartGiveResponses;
    }

    //查询sku参与赠送活动的赠优惠券
    public List<CartGiveResponse> selectSkuGiveCouponList(Integer belongType, Long activityId, Long skuId) {
        QActivityGoodsDO goodsDO = QActivityGoodsDO.activityGoodsDO;
        QActivityGoodsCouponDO activityGoodsCouponDO = QActivityGoodsCouponDO.activityGoodsCouponDO;

        BooleanBuilder predicates = new BooleanBuilder();
        predicates.and(goodsDO.belongType.eq(belongType));
        predicates.and(goodsDO.activityId.eq(activityId));
        predicates.and(goodsDO.skuId.eq(skuId));

        JPAQuery<CartGiveResponse> queryJpaQuery = queryFactory.select(Projections.bean(CartGiveResponse.class,
                activityGoodsCouponDO.id.as("giftId"),
                activityGoodsCouponDO.couponName.as("name"),
                activityGoodsCouponDO.couponId.as("id"),
                activityGoodsCouponDO.num,
                activityGoodsCouponDO.limitValue,
                activityGoodsCouponDO.groupNo))
                .from(goodsDO)
                .innerJoin(activityGoodsCouponDO).on(goodsDO.id.eq(activityGoodsCouponDO.activityGoods.id));
        queryJpaQuery.where(predicates);
        return queryJpaQuery.fetch();
    }

    //查询sku参与套餐活动的搭配商品
    public List<SubsidiaryDto> selectSkuSetMealList(Integer belongType,Long activityId, Long skuId,Integer groupNo) {
        return selectSubsidiaryList(belongType, activityId, skuId, groupNo);
    }

}
